//
//  QWImagePickerControllerViewController.m
//  OntheRoadV4
//
//  Created by hz on 7/10/13.
//  Copyright (c) 2013 EricHuang. All rights reserved.
//

#import "QWImagePickerControllerViewController.h"
#import "MyCameraExpandableButton.h"
#import "ALAssetsLibrary+CustomPhotoAlbum.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <ImageIO/ImageIO.h>
#import "AVCamCaptureManager.h"
#import "AVCamRecorder.h"
#import "AVCamUtilities.h"
#import <AVFoundation/AVFoundation.h>
#import "PHPhotoLibrary+CustomPhotoAlbum.h"
#import "QWImageMangerConfig.h"
#define DIFF_HEIGHT 0.0f

static void *AVCamFocusModeObserverContext = &AVCamFocusModeObserverContext;
static void *AVCamAdjustingFocusObserverContext = &AVCamAdjustingFocusObserverContext;

@interface QWImagePickerControllerViewController() <UIGestureRecognizerDelegate>
@end

@interface QWImagePickerControllerViewController (InternalMethods)
- (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates;
- (void)tapToAutoFocus:(UIGestureRecognizer *)gestureRecognizer;
- (void)tapToContinouslyAutoFocus:(UIGestureRecognizer *)gestureRecognizer;
- (void)updateButtonStates;
@end

@interface QWImagePickerControllerViewController (AVCamCaptureManagerDelegate) <AVCamCaptureManagerDelegate>
@end

@interface QWImagePickerControllerViewController () {
    NSInteger curFlashMode;
    BOOL canAccessCamera;
    BOOL needShowSkipBtn;
    
    BOOL firstLayout;
}

@property (nonatomic) BOOL isSwiping;
@property (nonatomic) NSInteger cameraViewHeight;
@property (nonatomic) CGPoint tapPoint;

@property (nonatomic, copy) NSArray *initialArray;

@property (nonatomic, strong) MyCameraExpandableButton *expandFlashBtn;

@end

@implementation QWImagePickerControllerViewController

@synthesize captureManager;
@synthesize cameraToggleButton;
@synthesize stillButton;
@synthesize videoPreviewView;
@synthesize captureVideoPreviewLayer;

- (NSString *)stringForFocusMode:(AVCaptureFocusMode)focusMode
{
	NSString *focusString = @"";
	
	switch (focusMode) {
		case AVCaptureFocusModeLocked:
			focusString = @"locked";
			break;
		case AVCaptureFocusModeAutoFocus:
			focusString = @"auto";
			break;
		case AVCaptureFocusModeContinuousAutoFocus:
			focusString = @"continuous";
			break;
	}
	
	return focusString;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    // 适配iPhone 4 和 5
    nibBundleOrNil = [QWImageMangerConfig baseBundle];
    if ([UIScreen mainScreen].bounds.size.height * SCREEN_SCALE < 961.0f) {
        nibNameOrNil = @"QWImagePickerControllerViewController_35";
    } else {
        nibNameOrNil = nil;
    }

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        self.wantsFullScreenLayout = YES;

        [self addObserver:self forKeyPath:@"captureManager.videoInput.device.focusMode" options:NSKeyValueObservingOptionNew context:AVCamFocusModeObserverContext];
        [self addObserver:self forKeyPath:@"captureManager.videoInput.device.adjustingFocus" options:NSKeyValueObservingOptionNew context:AVCamAdjustingFocusObserverContext];
    }
    return self;
}

- (id)initWithSelectedArray:(NSArray *)selectedArray hasSkipBtn:(BOOL)hasSkipBtn
{
    if (self = [super init]) {
        _initialArray = [selectedArray copy];
        needShowSkipBtn = hasSkipBtn;
    }
    return self;
}

- (id)initWithCaptureManager:(AVCamCaptureManager *)manager
                previewLayer:(AVCaptureVideoPreviewLayer *)previewLayer
{
    if (self = [super init]) {
        _initialArray = nil;
        needShowSkipBtn = NO;
        
        self.captureManager = manager;
        self.captureVideoPreviewLayer = previewLayer;
    }
    return self;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self removeObserver:self forKeyPath:@"captureManager.videoInput.device.focusMode"];
    [self removeObserver:self forKeyPath:@"captureManager.videoInput.device.adjustingFocus"];
    
    [captureManager setDelegate:nil];

//    if (captureManager) {
//        [captureManager setDelegate:nil];
//        [captureManager.positionIntervalTimer invalidate];
//        [captureManager.positioningTimer invalidate];
//        [captureManager removeObservrs];
//    }

}

- (BOOL)hasPermissionToAccessCamera
{
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
        
        if (authStatus == AVAuthorizationStatusAuthorized) {
            return YES;
        } else if (authStatus == AVAuthorizationStatusNotDetermined) {
//            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
//                if (granted) {
//                    [self setCaptureManager:nil];
//                    self.view = nil;
//                }
//            }];
            return YES;
        }
        
        NSDate *lastAlertDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"QWImagePickerNoPermissionAlertDate"];
        if (!lastAlertDate) {
            [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"QWImagePickerNoPermissionAlertDate"];
            
            UIAlertView * alert = [[UIAlertView alloc] initWithTitle:QWImagePickerLocalizedString(@"This app does not have access to your camera!", nil)
                                                             message:QWImagePickerLocalizedString(@"You can enable access in Privacy Settings.", nil)
                                                            delegate:nil
                                                   cancelButtonTitle:QWImagePickerLocalizedString(@"I know", nil)
                                                   otherButtonTitles:nil];
            [alert show];
        }
        
        return NO;
    } else {
        return YES;
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self.view setFrame:[UIScreen mainScreen].bounds];
    
    [self.cameraToggleButton setImage:[QWImageMangerConfig imageNamed:@"CameraFlipFrontRear.png"] forState:UIControlStateNormal];
    self.focusImageView.image = [QWImageMangerConfig imageNamed:@"focus-crosshair.png"];
    [self.stillButton setImage:[QWImageMangerConfig imageNamed:@"record_take.png"] forState:UIControlStateNormal];
    
    
    NSArray *flashBtnArr = @[QWImagePickerLocalizedString(@"Auto", nil),
                             QWImagePickerLocalizedString(@"On", nil),
                             QWImagePickerLocalizedString(@"Off", nil)];

    self.expandFlashBtn = [[MyCameraExpandableButton alloc] initWithPoint:CGPointMake(0.0f, 0.0f)
                                                                leftTitle:[QWImageMangerConfig  imageNamed:@"CameraFlashAuto"]
                                                                  buttons:flashBtnArr];
    [self.expandFlashBtn addTarget:self action:@selector(toggleFlashlight:) forControlEvents:UIControlEventValueChanged];
    self.expandFlashBtn.frame = self.flashContainerView.bounds;
    [self.flashContainerView addSubview:self.expandFlashBtn];

    self.videoPreviewView.backgroundColor = [UIColor blackColor];//[UIColor colorWithPatternImage:[QWImageMangerConfig  imageNamed:@"micro_carbon"]];
    self.shutterTopHalfView.backgroundColor = [UIColor colorWithPatternImage:[QWImageMangerConfig  imageNamed:@"micro_carbon"]];
    self.shutterBottomHalfView.backgroundColor = [UIColor colorWithPatternImage:[QWImageMangerConfig  imageNamed:@"micro_carbon"]];
    self.focusImageView.alpha = 0.0f;

    [self.stillButton    setHidden:NO];

    [self.cancelBtn setTitle:QWImagePickerLocalizedString(@"Cancel", nil) forState:UIControlStateNormal];

//    canAccessCamera = [self hasPermissionToAccessCamera];
//	if ([self captureManager] == nil && canAccessCamera) {
//		AVCamCaptureManager *manager = [[AVCamCaptureManager alloc] init];
//		[self setCaptureManager:manager];
//		[manager release];
//		
//		[[self captureManager] setDelegate:self];
//        
//		if ([[self captureManager] setupSession]) {
//            // Create video preview layer and add it to the UI
//			AVCaptureVideoPreviewLayer *newCaptureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:[[self captureManager] session]];
//			UIView *view = [self videoPreviewView];
//			CALayer *viewLayer = [view layer];
//			[viewLayer setMasksToBounds:YES];
//			
//			CGRect bounds = [view bounds];
//			[newCaptureVideoPreviewLayer setFrame:bounds];
//            
//            if ([newCaptureVideoPreviewLayer respondsToSelector:@selector(connection)]) {
//                if ([[newCaptureVideoPreviewLayer connection] isVideoOrientationSupported]) {
//                    [[newCaptureVideoPreviewLayer connection] setVideoOrientation:AVCaptureVideoOrientationPortrait];
//                }
//            } else {
//                if ([newCaptureVideoPreviewLayer isOrientationSupported]) {
//                    [newCaptureVideoPreviewLayer setOrientation:AVCaptureVideoOrientationPortrait];
//                }
//            }
//			
//			[newCaptureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
//			
//			[viewLayer insertSublayer:newCaptureVideoPreviewLayer below:[[viewLayer sublayers] objectAtIndex:0]];
//			
//			[self setCaptureVideoPreviewLayer:newCaptureVideoPreviewLayer];
//            [newCaptureVideoPreviewLayer release];
//			
//            // Start the session. This is done asychronously since -startRunning doesn't return until the session is running.
//			dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//				[[[self captureManager] session] startRunning];
//                dispatch_async(dispatch_get_main_queue(), ^{
//                    self.shutterTopHalfView.alpha = 0.0f;
//                    self.shutterBottomHalfView.alpha = 0.0f;
//                    
//                    // Add a single tap gesture to focus on the point tapped, then lock focus
//                    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToAutoFocus:)];
//                    [singleTap setDelegate:self];
//                    [singleTap setNumberOfTapsRequired:1];
//                    [view addGestureRecognizer:singleTap];
//                    [singleTap release];
//                    
//                    [self tapToContinouslyAutoFocus:nil];
//                });
//			});
//            
//            curFlashMode = [QWImageMangerConfig getLastFlashMode];
//            [self updateFlashBtnState:curFlashMode];
//
//            [self updateButtonStates];
//		}
//	}
    
    canAccessCamera = [self hasPermissionToAccessCamera];

    [[self captureManager] setDelegate:self];
    
    UIView *view = [self videoPreviewView];
    CALayer *viewLayer = [view layer];
    [viewLayer setMasksToBounds:YES];
    
    CGRect bounds = [view bounds];
    [captureVideoPreviewLayer setFrame:bounds];
    
    [viewLayer insertSublayer:captureVideoPreviewLayer below:[[viewLayer sublayers] firstObject]];
    
    self.shutterTopHalfView.alpha = 0.0f;
    self.shutterBottomHalfView.alpha = 0.0f;

    // Add a single tap gesture to focus on the point tapped, then lock focus
    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToAutoFocus:)];
    [singleTap setDelegate:self];
    [singleTap setNumberOfTapsRequired:1];
    [view addGestureRecognizer:singleTap];
    
//    [self tapToContinouslyAutoFocus:nil];
    
    curFlashMode = [QWImageMangerConfig getLastFlashMode];
    [self.expandFlashBtn setSelectedItem:curFlashMode];

    [self updateButtonStates];
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    
    if (!firstLayout) {
        [captureVideoPreviewLayer setFrame:[self videoPreviewView].bounds];
        [self tapToContinouslyAutoFocus:nil];
        
        firstLayout = YES;
        
        [self.view layoutIfNeeded];
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == AVCamAdjustingFocusObserverContext) {
        if ([change objectForKey:NSKeyValueChangeNewKey] == [NSNull null]) return;
        
        // Update the focus UI overlay string when the focus mode changes
        BOOL newValue = [[change objectForKey:NSKeyValueChangeNewKey] boolValue];
        if ([[[captureManager videoInput] device] focusMode] == AVCaptureFocusModeContinuousAutoFocus){
            if (newValue) {
                self.focusImageView.transform = CGAffineTransformMakeScale(0.75, 0.75);
                self.focusImageView.alpha = 1.0;
                self.focusImgLeadingSpaceConstraint.constant = self.videoPreviewView.bounds.size.width/2.0 - self.focusImageView.frame.size.width / 2.0f;
                self.focusImgTopSpaceConstraint.constant = self.videoPreviewView.bounds.size.height/2.0 - self.focusImageView.frame.size.height / 2.0f;
                [self.focusImageView layoutIfNeeded];
                
                CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
                [animation setFromValue:[NSNumber numberWithFloat:1.0]];
                [animation setToValue:[NSNumber numberWithFloat:0.3]];
                [animation setDuration:0.15f];
                [animation setTimingFunction:[CAMediaTimingFunction
                                              functionWithName:kCAMediaTimingFunctionLinear]];
                [animation setAutoreverses:YES];
                [animation setRepeatCount:20000];
                [[self.focusImageView layer] addAnimation:animation forKey:@"opacity"];
            } else {
                self.focusImageView.alpha = 0.0f;
                [[self.focusImageView layer] removeAllAnimations];
            }
        }
	}
    else if (context == AVCamFocusModeObserverContext) {
        if ([change objectForKey:NSKeyValueChangeNewKey] == [NSNull null]) return;

        AVCaptureFocusMode focusMode = [[change objectForKey:NSKeyValueChangeNewKey] intValue];
        if (focusMode == AVCaptureFocusModeLocked) {
            self.focusImageView.alpha = 0.0f;
            [[self.focusImageView layer] removeAllAnimations];
        } else if (focusMode == AVCaptureFocusModeContinuousAutoFocus &&
                   [[[captureManager videoInput] device] isFocusPointOfInterestSupported]) {
            self.focusImageView.transform = CGAffineTransformMakeScale(0.75, 0.75);
            self.focusImageView.alpha = 1.0;
            self.focusImgLeadingSpaceConstraint.constant = self.videoPreviewView.bounds.size.width/2.0 - self.focusImageView.frame.size.width / 2.0f;
            self.focusImgTopSpaceConstraint.constant = self.videoPreviewView.bounds.size.height/2.0 - self.focusImageView.frame.size.height / 2.0f;
            [self.focusImageView layoutIfNeeded];

            CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
            [animation setFromValue:[NSNumber numberWithFloat:1.0]];
            [animation setToValue:[NSNumber numberWithFloat:0.3]];
            [animation setDuration:0.15f];
            [animation setTimingFunction:[CAMediaTimingFunction
                                          functionWithName:kCAMediaTimingFunctionLinear]];
            [animation setAutoreverses:YES];
            [animation setRepeatCount:20000];
            [[self.focusImageView layer] addAnimation:animation forKey:@"opacity"];
        }
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)viewDidUnload {
    [self setCancelBtn:nil];
    [self setToolBarView:nil];
    [self setFocusImageView:nil];
    [self setShutterTopHalfView:nil];
    [self setShutterBottomHalfView:nil];
    [self setToggleFlashBtn:nil];
    [super viewDidUnload];
}

// support iOS6 rotate
//-(UIInterfaceOrientationMask)supportedInterfaceOrientations
//{
//    return UIInterfaceOrientationMaskPortrait;
//}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark user interaction

#ifndef currentappDelegate
#define currentappDelegate [[UIApplication sharedApplication] delegate]
#endif

-(void)viewWillAppear:(BOOL)animated
{

    [super viewWillAppear:animated];
    
    if ([currentappDelegate respondsToSelector:@selector(hideWindowToast)])
    {
        [currentappDelegate performSelector:@selector(hideWindowToast)];
    }
    
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
    [self.navigationController setNavigationBarHidden:YES];

    // 切换到输出格式到拍照模式
    if ([[[self captureManager] session] sessionPreset] != AVCaptureSessionPresetPhoto) {
        self.blurOverlayImgView.alpha = 1.0f;

        dispatch_async(dispatch_get_main_queue(), ^{
            [[[self captureManager] session] beginConfiguration];
            [[[self captureManager] session] setSessionPreset:AVCaptureSessionPresetPhoto];
            [[[self captureManager] session] commitConfiguration];
            
            [UIView animateWithDuration:0.3f
                             animations:^{
                                 self.blurOverlayImgView.alpha = 0.0f;
                                 self.shutterTopHalfView.alpha = 0.0f;
                                 self.shutterBottomHalfView.alpha = 0.0f;
                             }];
        });
    } else {
        [UIView animateWithDuration:0.15f animations:^{
            self.shutterTopHalfView.alpha = 0.0f;
            self.shutterBottomHalfView.alpha = 0.0f;
        }];
    }

    [self.captureManager startMotionDetecting];
}



-(void)viewWillDisappear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super viewWillDisappear:animated];

    if ([self.navigationController.viewControllers objectAtIndex:0] != self &&
        ![self.navigationController.viewControllers containsObject:self]) {
        [self.navigationController setNavigationBarHidden:NO];
        [[UIApplication sharedApplication] setStatusBarHidden:NO];
    }

    [self.captureManager stopMotionDetecting];
}

-(void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

// flash mode: 0:auto, 1:on, 2:off
- (void)updateFlashBtnState:(NSInteger)flashMode
{
    switch (flashMode) {
        case 0:
            [self.captureManager setFlashMode:AVCaptureFlashModeAuto];
            [QWImageMangerConfig setLastFlashMode:flashMode];
            break;
        case 1:
            [self.captureManager setFlashMode:AVCaptureFlashModeOn];
            [QWImageMangerConfig setLastFlashMode:flashMode];
            break;
        case 2:
            [self.captureManager setFlashMode:AVCaptureFlashModeOff];
            [QWImageMangerConfig setLastFlashMode:flashMode];
            break;
        default:
            [self.captureManager setFlashMode:AVCaptureFlashModeAuto];
            [QWImageMangerConfig setLastFlashMode:0];
            break;
    }
}

- (void)toggleFlashlight:(DDExpandableButton *)sender
{
    [self updateFlashBtnState:sender.selectedItem];
}

- (IBAction)cameraBtnPressed:(id)sender
{
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:QWImagePickerLocalizedString(@"No connected camera", nil)
                                                            message:nil delegate:nil
                                                  cancelButtonTitle:QWImagePickerLocalizedString(@"OK", nil)
                                                  otherButtonTitles:nil];
        [alertView show];
    }
}

- (IBAction)cancelBtnPressed:(id)sender
{
#warning 友盟统计
   // [MobClick event:CameraClose];

    if (self.delegate) {
        if ([self.delegate respondsToSelector:@selector(didCancelCameraAnimated:)]) {
            [self.delegate didCancelCameraAnimated:YES];
        }
    }
}

#pragma mark Toolbar Actions
- (IBAction)toggleCamera:(id)sender
{
    // Toggle between cameras when there is more than one
    [[self captureManager] toggleCamera];
    
    // Do an initial focus
    [[self captureManager] continuousFocusAtPoint:CGPointMake(.5f, .5f)];
    
    // update button status
    [self updateButtonStates];
}

- (IBAction)captureStillImage:(id)sender
{
    #warning 友盟统计
   // [MobClick event:CameraTakePhoto];
    // Capture a still image
    [[self stillButton] setEnabled:NO];
    
    if (![[self captureManager] captureStillImage]) {
        [[self stillButton] setEnabled:YES];
        return;
    }
    
    CGRect previewFrame = self.shutterTopHalfView.bounds;
    self.shutterTopHalfView.frame = previewFrame;
    previewFrame.origin.y += previewFrame.size.height;
    previewFrame.size.height = self.shutterBottomHalfView.frame.size.height;
    self.shutterBottomHalfView.frame = previewFrame;
    self.shutterTopHalfView.alpha = 0.0;
    self.shutterBottomHalfView.alpha = 0.0;
    
    [UIView animateWithDuration:0.3f
                          delay:0
                        options:UIViewAnimationOptionCurveEaseInOut
                     animations:^{
                         self.shutterTopHalfView.alpha = 1.0;
                         self.shutterBottomHalfView.alpha = 1.0;
                          
                         CGRect tempFrame = self.shutterTopHalfView.frame;
                         tempFrame.origin.y -= tempFrame.size.height;
                         self.shutterTopHalfView.frame = tempFrame;
                         tempFrame =  self.shutterBottomHalfView.frame;
                         tempFrame.origin.y += tempFrame.size.height;
                         self.shutterBottomHalfView.frame = tempFrame;
                     }completion:^(BOOL finished) {
                         self.shutterTopHalfView.alpha = 0.0f;
                         self.shutterBottomHalfView.alpha = 0.0f;
                     }];

//    // Flash the screen white and fade it out to give UI feedback that a still image was taken
//    CGRect flashViewFrame = [[self videoPreviewView] frame];
//    if ([[UIDevice currentDevice] resolution] != UIDeviceResolution_iPhoneRetina4) {
//        flashViewFrame.size.height -= 22;
//    }
//    UIView *flashView = [[UIView alloc] initWithFrame:flashViewFrame];
////    [flashView setBackgroundColor:[UIColor whiteColor]];
//    [flashView setBackgroundColor:[UIColor colorWithPatternImage:[QWImageMangerConfig  imageNamed:@"micro_carbon"]]];
//    [[[self view] window] addSubview:flashView];
//    
//    [UIView animateWithDuration:.4f
//                     animations:^{
//                         [flashView setAlpha:0.f];
//                     }
//                     completion:^(BOOL finished){
//                         [flashView removeFromSuperview];
//                         [flashView release];
//                     }
//     ];
}

#pragma mark -
#pragma mark handle gestrure event

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO || !canAccessCamera) {
        self.stillButton.enabled = NO;
        self.cancelBtn.hidden = NO;
        for (UIGestureRecognizer *recg in self.toolBarView.gestureRecognizers) {
            [self.toolBarView removeGestureRecognizer:recg];
        }
    }
}

@end

@implementation QWImagePickerControllerViewController (InternalMethods)

// Convert from view coordinates to camera coordinates, where {0,0} represents the top left of the picture area, and {1,1} represents
// the bottom right in landscape mode with the home button on the right.
- (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates
{
    CGPoint pointOfInterest = CGPointMake(.5f, .5f);
    CGSize frameSize = [[self videoPreviewView] frame].size;
    
    if ([captureVideoPreviewLayer respondsToSelector:@selector(connection)]) {
        if ([[captureVideoPreviewLayer connection] isVideoMirrored]) {
            viewCoordinates.x = frameSize.width - viewCoordinates.x;
        }
    } else {
        if ([captureVideoPreviewLayer isMirrored]) {
            viewCoordinates.x = frameSize.width - viewCoordinates.x;
        }
    }
    
    if ( [[captureVideoPreviewLayer videoGravity] isEqualToString:AVLayerVideoGravityResize] ) {
		// Scale, switch x and y, and reverse x
        pointOfInterest = CGPointMake(viewCoordinates.y / frameSize.height, 1.f - (viewCoordinates.x / frameSize.width));
    } else {
        CGRect cleanAperture;
        for (AVCaptureInputPort *port in [[[self captureManager] videoInput] ports]) {
            if ([port mediaType] == AVMediaTypeVideo) {
                cleanAperture = CMVideoFormatDescriptionGetCleanAperture([port formatDescription], YES);
                CGSize apertureSize = cleanAperture.size;
                CGPoint point = viewCoordinates;
                
                CGFloat apertureRatio = apertureSize.height / apertureSize.width;
                CGFloat viewRatio = frameSize.width / frameSize.height;
                CGFloat xc = .5f;
                CGFloat yc = .5f;
                
                if ( [[captureVideoPreviewLayer videoGravity] isEqualToString:AVLayerVideoGravityResizeAspect] ) {
                    if (viewRatio > apertureRatio) {
                        CGFloat y2 = frameSize.height;
                        CGFloat x2 = frameSize.height * apertureRatio;
                        CGFloat x1 = frameSize.width;
                        CGFloat blackBar = (x1 - x2) / 2;
						// If point is inside letterboxed area, do coordinate conversion; otherwise, don't change the default value returned (.5,.5)
                        if (point.x >= blackBar && point.x <= blackBar + x2) {
							// Scale (accounting for the letterboxing on the left and right of the video preview), switch x and y, and reverse x
                            xc = point.y / y2;
                            yc = 1.f - ((point.x - blackBar) / x2);
                        }
                    } else {
                        CGFloat y2 = frameSize.width / apertureRatio;
                        CGFloat y1 = frameSize.height;
                        CGFloat x2 = frameSize.width;
                        CGFloat blackBar = (y1 - y2) / 2;
						// If point is inside letterboxed area, do coordinate conversion. Otherwise, don't change the default value returned (.5,.5)
                        if (point.y >= blackBar && point.y <= blackBar + y2) {
							// Scale (accounting for the letterboxing on the top and bottom of the video preview), switch x and y, and reverse x
                            xc = ((point.y - blackBar) / y2);
                            yc = 1.f - (point.x / x2);
                        }
                    }
                } else if ([[captureVideoPreviewLayer videoGravity] isEqualToString:AVLayerVideoGravityResizeAspectFill]) {
					// Scale, switch x and y, and reverse x
                    if (viewRatio > apertureRatio) {
                        CGFloat y2 = apertureSize.width * (frameSize.width / apertureSize.height);
                        xc = (point.y + ((y2 - frameSize.height) / 2.f)) / y2; // Account for cropped height
                        yc = (frameSize.width - point.x) / frameSize.width;
                    } else {
                        CGFloat x2 = apertureSize.height * (frameSize.height / apertureSize.width);
                        yc = 1.f - ((point.x + ((x2 - frameSize.width) / 2)) / x2); // Account for cropped width
                        xc = point.y / frameSize.height;
                    }
                }
                
                pointOfInterest = CGPointMake(xc, yc);
                break;
            }
        }
    }
    
    return pointOfInterest;
}

// Auto focus at a particular point. The focus mode will change to locked once the auto focus happens.
- (void)tapToAutoFocus:(UIGestureRecognizer *)gestureRecognizer
{
    if ([[[captureManager videoInput] device] isFocusPointOfInterestSupported] ||
        [[[captureManager videoInput] device] isExposurePointOfInterestSupported]) {
        CGPoint tapPoint = [gestureRecognizer locationInView:[self videoPreviewView]];
        CGPoint convertedFocusPoint = [self convertToPointOfInterestFromViewCoordinates:tapPoint];
        self.tapPoint = tapPoint;
        [captureManager autoFocusAtPoint:convertedFocusPoint];
        
        self.focusImageView.transform = CGAffineTransformMakeScale(0.75, 0.75);
        self.focusImageView.alpha = 0;
        self.focusImgLeadingSpaceConstraint.constant = self.tapPoint.x - self.focusImageView.frame.size.width / 2.0f;
        self.focusImgTopSpaceConstraint.constant = self.tapPoint.y - self.focusImageView.frame.size.height / 2.0f;
        [self.focusImageView layoutIfNeeded];

        void (^animations)(void) = ^{
            self.focusImageView.transform = CGAffineTransformMakeScale(0.5, 0.5);
            self.focusImageView.alpha = 1;
        };
        
        [UIView animateWithDuration:0.2 animations:animations completion:^(BOOL finished){
            if (finished) {
                if (![[[captureManager videoInput] device] isFocusPointOfInterestSupported]) {
                    [UIView animateWithDuration:0.2 animations:^{
                        self.focusImageView.alpha = 0.0f;
                    } completion:^(BOOL finsished) {
                        [[self.focusImageView layer] removeAllAnimations];
                    }];
                } else {
                    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
                    [animation setFromValue:[NSNumber numberWithFloat:1.0]];
                    [animation setToValue:[NSNumber numberWithFloat:0.3]];
                    [animation setDuration:0.15f];
                    [animation setTimingFunction:[CAMediaTimingFunction
                                                  functionWithName:kCAMediaTimingFunctionLinear]];
                    [animation setAutoreverses:YES];
                    [animation setRepeatCount:20000];
                    [[self.focusImageView layer] addAnimation:animation forKey:@"opacity"];
                }
            }
        }];
    }
}

// Change to continuous auto focus. The camera will constantly focus at the point choosen.
- (void)tapToContinouslyAutoFocus:(UIGestureRecognizer *)gestureRecognizer
{
    if ([[[captureManager videoInput] device] isFocusPointOfInterestSupported])
        [captureManager continuousFocusAtPoint:CGPointMake(.5f, .5f)];
}

// Update button states based on the number of available cameras and mics
- (void)updateButtonStates
{
	NSUInteger cameraCount = [[self captureManager] cameraCount];
    
    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^(void) {
        if (cameraCount < 2) {
            [[self cameraToggleButton] setHidden:YES];
            
            if (cameraCount < 1) {
                [[self stillButton] setEnabled:NO];
            } else {
                [[self stillButton] setEnabled:YES];
            }
        } else {
            [[self cameraToggleButton] setHidden:NO];
            [[self stillButton] setEnabled:YES];
        }
        
        if ([[[self.captureManager videoInput] device] hasFlash]) {
            self.toggleFlashBtn.hidden = NO;
        } else {
            self.toggleFlashBtn.hidden = YES;
        }
    });
}

@end

@implementation QWImagePickerControllerViewController (AVCamCaptureManagerDelegate)


- (void)captureManager:(AVCamCaptureManager *)captureManager didFailWithError:(NSError *)error
{
    CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^(void) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[error localizedDescription]
                                                            message:[error localizedFailureReason]
                                                           delegate:nil
                                                  cancelButtonTitle:QWImagePickerLocalizedString(@"OK", @"OK button title")
                                                  otherButtonTitles:nil];
        [alertView show];
    });
}

- (void)captureManagerStillImageCaptured:(AVCamCaptureManager *)captureManager withInfo:(NSDictionary *)info
{
    if (self.delegate && [self.delegate respondsToSelector:@selector(didFinishTakeAImage:)]) {
        [self.delegate didFinishTakeAImage:info];
        CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^(void) {
            [[self stillButton] setEnabled:YES];
        });
    } else {
        UIImage *image = [info objectForKey:@"Image"];
        NSDictionary *metaData = [info objectForKey:@"metadata"];
        if (NSClassFromString(@"PHPhotoLibrary"))
        {
            PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
            [library saveImage:image toAlbum:APP_ALBUM_NAME withMetaData:metaData withCompletionBlock:^(NSString *identifiers, NSError *error) {
                if (error!=nil) {
                    //DebugLog(@"Failed to write image: %@", [error description]);
                } else {
                    //                [self.libraryPicker takeAPicture:assetURL];
                }
                // FIXZHY retry? No, we wait for write done now
                
                CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^(void) {
                    [[self stillButton] setEnabled:YES];
                });

            }];
        }else
        {
            ALAssetsLibrary *library = [QWImageMangerConfig sharedAssetsLibrary];
            [library saveImage:image toAlbum:nil withMetaData:metaData withCompletionBlock:^(NSURL *assetURL, NSError *error) {
                if (error!=nil) {
                    //DebugLog(@"Failed to write image: %@", [error description]);
                    if ([error code] == ALAssetsLibraryWriteBusyError) {
                        return;
                    }
                } else {
                    //                [self.libraryPicker takeAPicture:assetURL];
                }
                // FIXZHY retry? No, we wait for write done now
                
                CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^(void) {
                    [[self stillButton] setEnabled:YES];
                });
            }];
        }
       
    }
}

- (void)captureManagerDeviceConfigurationChanged:(AVCamCaptureManager *)captureManager
{
	[self updateButtonStates];
}

@end
